package com.qf.osmorder.order.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.qf.api.recharge.feign.RechargeFeignService;
import com.qf.common.core.dto.BalanceChangeDTO;
import com.qf.common.core.entity.Recharge;
import com.qf.common.core.util.UserUtils;
import com.qf.common.pay.dto.PayDTO;
import com.qf.common.pay.param.FinishPayParam;
import com.qf.common.pay.param.RefundParam;
import com.qf.common.pay.service.PayService;
import com.qf.common.redis.utils.RedisUtil;
import com.qf.osmorder.order.dto.RechargeOrderDTO;
import com.qf.osmorder.order.mapper.RechargeMapper;
import com.qf.osmorder.order.service.OrderService;
import com.xxl.job.core.handler.annotation.XxlJob;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author TianWenHe
 * @date 2025/6/11
 * @desc
 */
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {
    @Autowired
    private RechargeMapper rechargeMapper;
    @Autowired
    private RechargeFeignService rechargeFeignService;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Resource(name = "aliPayServiceImpl")
    private PayService aliPayService;
    @Autowired
    private RedissonClient redissonClient;

    /**
     * 生成充值订单
     */
    @Override
    public String addRechargeOrder(RechargeOrderDTO rechargeOrderDTO) {
        log.info("开始生成订单");
        Recharge recharge = Recharge.builder()
                .uid(UserUtils.getUid())
                .amount(rechargeOrderDTO.getAmount().setScale(2, RoundingMode.HALF_UP))
                .orderNo(UUID.randomUUID().toString().replace("-", ""))
                .platform(rechargeOrderDTO.getPayPlatform())
                .build();
        rechargeMapper.insert(recharge);
        return recharge.getOrderNo();
    }

    /**
     * 预支付
     */
    @Override
    public String prePay(PayDTO payDTO) {
        // 如果平台为1，则调用微信支付接口，2则调用支付宝接口
        if (payDTO.getPayPlatform() == 1) {
            log.info("开始调用微信支付接口");
            return null;
        }else if (payDTO.getPayPlatform() == 2) {
            return aliPayService.createPay(payDTO);
        }
        return "无效的支付平台";
    }

    /**
     * 异步回调
     */
    @GlobalTransactional(rollbackFor = Exception.class)
    @Override
    public void notify(HttpServletRequest request, HttpServletResponse response) {
        aliPayService.notify(request, response, param -> {
            // 这里处理支付成功的业务逻辑，比如更新订单状态
            // 查询 orderNo 对应的数据
            Recharge recharge = rechargeMapper.selectOne(Wrappers.<Recharge>lambdaQuery()
                    .eq(Recharge::getOrderNo, param.getOutTradeNo()));
            if (recharge == null) {
                throw new RuntimeException("未找到对应的订单");
            }

            rechargeSuccess(param.getTradeNo(), recharge);
        });
    }

    /**
     * 充值成功业务逻辑
     */
    private void rechargeSuccess(String tradeNo, Recharge recharge) {
        String lockKey = "lock:recharge_success:" + recharge.getId();
        RLock lock = redissonClient.getLock(lockKey);

        try {
            // 尝试获取锁，等待时间为 10 秒，持有锁时间为 30 秒
            if (lock.tryLock(10, 30, TimeUnit.SECONDS)) {
                // 重新加载最新数据，避免脏读
                recharge = rechargeMapper.selectById(recharge.getId());

                // 如果交易号已存在，说明已被其他线程处理过了
                if (recharge.getTradeNo() != null && !recharge.getTradeNo().isEmpty()) {
                    return;
                }

                // 验证状态是否合法
                if (recharge.getStatus() != 1 && recharge.getStatus() != 3) {
                    throw new RuntimeException("订单状态异常");
                }

                // 设置交易号并更新状态
                recharge.setStatus(2);
                recharge.setTradeNo(tradeNo);
                rechargeMapper.updateById(recharge);

                // 生成一次性 Token
                String internalToken = UUID.randomUUID().toString().replace("-", "");
                redisTemplate.opsForValue().set("internal_token:" + internalToken, "valid", 60, TimeUnit.SECONDS);

                // 调用用户服务修改余额
                rechargeFeignService.changeBalance(BalanceChangeDTO.builder()
                        .amount(recharge.getAmount())
                        .userId(recharge.getUid())
                        .internalToken(internalToken)
                        .build());

                log.info("支付成功，交易订单号：{}", tradeNo);
            } else {
                log.warn("未能获取到锁，跳过充值逻辑。订单ID：{}", recharge.getId());
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("获取分布式锁时发生中断异常", e);
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock(); // 只释放自己持有的锁
            }
        }
    }

    /**
     * 退款
     */
    @GlobalTransactional(rollbackFor = Exception.class)
    @Override
    public String refundOrder(RefundParam refundParam) {
        // 查询订单
        Recharge recharge = rechargeMapper.selectOne(Wrappers.<Recharge>lambdaQuery()
                .eq(Recharge::getOrderNo, refundParam.getOrderNo()));
        if (recharge == null) {
            throw new RuntimeException("未找到对应的订单");
        }

        // 如果uid不匹配，则抛出异常
        if (!Objects.equals(recharge.getUid(), UserUtils.getUid())) {
            throw new RuntimeException("用户不匹配");
        }

        // 更新订单状态为 4（已退款）
        if (recharge.getStatus() != 2){
            throw new RuntimeException("订单状态异常");
        }
        recharge.setStatus(4);
        rechargeMapper.updateById(recharge);

        // 调用远程服务修改用户余额
        // 生成一次性 Token
        String internalToken = UUID.randomUUID().toString().replace("-", "");
        redisTemplate.opsForValue().set("internal_token:" + internalToken, "valid", 60, TimeUnit.SECONDS);

        // 调用 changeBalanceFeignService 减少用户余额
        rechargeFeignService.changeBalance(BalanceChangeDTO.builder()
                .amount(refundParam.getRefundAmount().negate())  // 使用负数来减少余额
                .userId(recharge.getUid())
                .internalToken(internalToken)
                .build());
        String tradeNo = aliPayService.refundOrder(refundParam);
        log.info("订单退款成功，业务订单号：{}", refundParam.getOrderNo());
        return tradeNo;
    }

    /**
     * 同步回调
     */
    @GlobalTransactional(rollbackFor = Exception.class)
    @Override
    public void returnNotify(HttpServletRequest request, HttpServletResponse response) {
        aliPayService.returnNotify(request, response,param -> {
            // 这里处理支付成功的业务逻辑，比如更新订单状态
            // 查询 orderNo 对应的数据
            Recharge recharge = rechargeMapper.selectOne(Wrappers.<Recharge>lambdaQuery()
                    .eq(Recharge::getOrderNo, param.getOutTradeNo()));
            if (recharge == null) {
                throw new RuntimeException("未找到对应的订单");
            }

            rechargeSuccess(param.getTradeNo(), recharge);
        });
    }

    /**
     * 定时任务，掉单处理
     */
    @GlobalTransactional(rollbackFor = Exception.class)
    @Override
    public void checkRechargeOrders() {
        // 查询所有订单状态为1的订单
        List<Recharge> pendingOrders = rechargeMapper.selectList(Wrappers.<Recharge>lambdaQuery()
                .eq(Recharge::getStatus, 1)); // status=1 表示待支付

        if(pendingOrders.isEmpty()){
            return;
        }

        for (Recharge recharge : pendingOrders) {
            Integer retryCount = recharge.getRetryCount();

            if (retryCount >= 12) {
                // 已重试12次仍无法获取交易号，关闭订单
                try {
                    aliPayService.closePay(recharge.getOrderNo());
                } catch (Exception e) {
                    log.error("关闭订单失败：{}", recharge.getOrderNo(), e);
                }

                // 更新订单状态为3（已取消）
                recharge.setStatus(3); // 状态3表示用户取消或超时
                rechargeMapper.updateById(recharge);
                continue;
            }

            // 主动调用支付宝查询订单状态
            String tradeNo;
            try {
                tradeNo = aliPayService.payStatus(recharge.getOrderNo());
            } catch (Exception e) {
                // 如果异常发生，增加重试次数
                recharge.setRetryCount(retryCount + 1);
                rechargeMapper.updateById(recharge);
                log.warn("查询订单状态失败，重试次数+1: {}", recharge.getOrderNo());
                continue;
            }

            // 如果成功获取到交易号，执行业务逻辑
            if (tradeNo != null && !tradeNo.isEmpty()) {
                rechargeSuccess(tradeNo, recharge);
            } else {
                // 未找到交易号，增加重试次数
                recharge.setRetryCount(retryCount + 1);
                rechargeMapper.updateById(recharge);
            }
        }
    }
}
